﻿using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

namespace ZFramework.Runtime
{
    public class FguiUIMgr : FrameworkManagerBase, IUIMgr
    {
        private int _serialId;
        private Dictionary<string, UIGroup> _uiGroups; //所有的ui group
        private Queue<IUIForm> _recycleQueue;
        private ObjectPoolMgr.ObjectPool<UIFormInstanceObject> _instancePool;
        private IEventManager _eventMgr;
        private ObjectPoolMgr _objectPoolMgr;
        private IUIFormHelper _uiFormHelper;

        private string _uiFormHelperName = "ZGame.FGuiUIFormHelper";
        private float _autoReleaseInterval = 60;
        private int _capacity = 10;
        private float _expireTime = 30;

        protected override void Awake()
        {
            base.Awake();
            _serialId = 0;
            _uiGroups = new Dictionary<string, UIGroup>();
            _recycleQueue = new Queue<IUIForm>();
        }

        void Start()
        {
            _eventMgr = FrameworkManagerManager.GetManager<EventManager>();
            if (_eventMgr == null)
            {
                Log.Error("EventMgr is invalid.");
                return;
            }
            _objectPoolMgr = FrameworkManagerManager.GetManager<ObjectPoolMgr>();
            if (_objectPoolMgr == null)
            {
                Log.Error("ObjectPoolMgr is invalid.");
                return;
            }
            _instancePool = _objectPoolMgr.CreateSingleSpawnObjectPool<UIFormInstanceObject>("UIFormPool", _autoReleaseInterval,
                _capacity, _expireTime);
            if (string.IsNullOrEmpty(_uiFormHelperName))
            {
                Log.Error("FguiUIMgr _uiFormHelperName 为空");
                return;
            }

            var helperGo = new GameObject(Utility.Text.Format("UIFormHelper-{0}", _uiFormHelperName));
            var trans = helperGo.transform;
            trans.SetParent(transform);
            Type helperType = Utility.Assembly.GetType(_uiFormHelperName);
            _uiFormHelper = (IUIFormHelper)helperGo.AddComponent(helperType);
            
            if (_uiFormHelper == null)
            {
                Log.Error("FguiUIMgr helper不是 IUIFormHelper 类型的, name=={0}", _uiFormHelperName);
                return;
            }
            var fGuiContentScaleHelper = new GameObject("fGuiContentScaleHelper");
            trans = fGuiContentScaleHelper.transform;
            trans.SetParent(transform);
            fGuiContentScaleHelper.AddComponent<FGuiContentScaleHelper>();
        }

        public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            while (_recycleQueue.Count > 0)
            {
                var uiForm = _recycleQueue.Dequeue();
                uiForm.OnRecycle();
                _instancePool.UnSpawn(uiForm.Obj);
            }

            foreach (var item in _uiGroups)
            {
                item.Value.Update(elapseSeconds, realElapseSeconds);
            }
        }

        public override void Shutdown()
        {
        }


        public void SetObjectPoolMgr(ObjectPoolMgr objectPoolMgr, float autoReleaseInterval, int capacity, float expireTime)
        {
            _objectPoolMgr = objectPoolMgr;
            _instancePool = _objectPoolMgr.CreateSingleSpawnObjectPool<UIFormInstanceObject>("UIFormPool", autoReleaseInterval,
                capacity, expireTime);
        }
        
        public bool AddUIGroup<T>(string uiGroupName, int depth) where T : MonoBehaviour, IUIGroupHelper
        {
            if (HasUIGroup(uiGroupName))
            {
                Log.Error("AddUIGroup uiGroupName 重复 name=={0}", uiGroupName);
                return false;
            }
            var goUIGroupHelper = new GameObject(uiGroupName).AddComponent<T>();
            goUIGroupHelper.gameObject.layer = LayerMask.NameToLayer("UI");
            Transform trans = goUIGroupHelper.transform;
            trans.SetParent(transform);
            trans.localScale = Vector3.one;
            return AddUIGroup(uiGroupName, depth, goUIGroupHelper);
        }
        
        private bool AddUIGroup(string uiGroupName, int depth, IUIGroupHelper uiGroupHelper)
        {
            if (HasUIGroup(uiGroupName))
            {
                Log.Error("AddUIGroup uiGroupName 重复 name=={0}", uiGroupName);
                return false;
            }

            if (uiGroupHelper == null)
            {
                throw new Exception(Utility.Text.Format("AddUIGroup 必须要有IUIGroupHelper  groupName=={0}", uiGroupName));
            }

            _uiGroups.Add(uiGroupName, new UIGroup(uiGroupName, depth, uiGroupHelper));
            return true;
        }

        public bool HasUIGroup(string uiGroupName)
        {
            if (_uiGroups.ContainsKey(uiGroupName))
                return true;
            return false;
        }

        public int OpenUI(string uiAssetPath, string uiGroupName, bool pauseCoverdUIForm, object userData)
        {
            throw new Exception("FguiUIMgr OpenUI 暂不支持使用路径打开UI，请调用另外的接口");
        }

        public void CloseUI(int serialId, object userData = null)
        {
            IUIForm uiForm = GetUIForm(serialId);
            if (uiForm == null)
            {
                Log.Error("CloseUI 找不到serialId=={0}的ui", serialId);
                return;
            }

            CloseUI(uiForm, userData);
        }
        
        public void CloseUI(IUIForm uiForm, object userData = null)
        {
            if (uiForm == null)
            {
                Log.Error("CloseUI uiForm为空");
                return;
            }

            UIGroup uiGroup = (UIGroup)uiForm.UIGroup;
            if (uiGroup == null)
            {
                Log.Error("CloseUI UIGroup 为空");
                return;
            }

            uiGroup.RemoveUIForm(uiForm);
            uiForm.OnClose(false, userData);
            uiGroup.Refresh();

            _eventMgr.Fire(this, CloseUIFormCompleteEventArgs.Create(uiForm.SerialId));

            _recycleQueue.Enqueue(uiForm);
        }

        public IUIForm GetUIForm(int serialId)
        {
            foreach (var item in _uiGroups)
            {
                var uiGroup = item.Value;
                var uiForm = uiGroup.GetUIForm(serialId);
                if (uiForm != null)
                {
                    return uiForm;
                }
            }

            return null;
        }
        
        public int OpenUI<T>(string uiGroupName, bool pauseCoveredUIForm, object userData) where T : UIFormLogic
        {
            var uiGroup = GetUIGroup(uiGroupName);
            if (uiGroup == null)
            {
                throw new Exception($"必须先创建uigroup，name=={uiGroupName}");
            }
            
            var type = typeof(T);
            string uiAssetPath = type.FullName;
            
            int serialId = ++_serialId;
            var instanceObject = _instancePool.Spawn(uiAssetPath);
            if (instanceObject == null)
            {
                var uiGo = new GameObject(uiAssetPath);
                uiGo.AddComponent<T>();
                var uiFormInstanceObject = UIFormInstanceObject.Create(uiAssetPath, null, uiGo, _uiFormHelper);
                _instancePool.Register(uiFormInstanceObject, true);
                InternalOpenUI(serialId, uiAssetPath, uiGroup, (Object)uiGo, pauseCoveredUIForm, true, 0,
                    userData);
            }
            else
            {
                InternalOpenUI(serialId, uiAssetPath, uiGroup, (Object)instanceObject.Instance, pauseCoveredUIForm, false, 0,
                    userData);
            }

            return serialId;
        }
        
        public UIGroup GetUIGroup(string uiGroupName)
        {
            if (_uiGroups.TryGetValue(uiGroupName, out var uiGroup))
            {
                return uiGroup;
            }

            return null;
        }
        
        private void InternalOpenUI(int serialId, string assetPath, UIGroup uiGroup, Object uiInstance,
            bool pauseCoveredUIForm, bool isNewInstance, float duration, object userData)
        {
            try
            {
                IUIForm uiForm = _uiFormHelper.CreateUIForm(uiInstance, uiGroup, userData);
                if (uiForm == null)
                {
                    throw new Exception($"不能创建uiform， path=={assetPath}");
                }

                uiForm.OnInit(serialId, assetPath, uiGroup, pauseCoveredUIForm, isNewInstance, userData);
                uiGroup.AddUIForm(uiForm);
                uiForm.OnOpen(userData);
                uiGroup.Refresh();

                _eventMgr.Fire(this, OpenUIFormSuccessEventArgs.Create(uiForm, duration, userData));
            }
            catch (Exception e)
            {
                _eventMgr.Fire(this, OpenUIFormFailureEventArgs.Create(serialId));
                throw;
            }
        }
    }
}